#include "serializer/serializer.h"
#include "serializer/traits.h"

#include <gtest/gtest.h>

#include <queue>
#include <stack>
#include <string>
#include <vector>

using namespace serializer;

/**
 * 将 stack 中的元素按弹出顺序收集到向量
 * 参数:
 * - st 输入的栈（按值传递，保留原对象不变）
 * 返回值: 依次弹出得到的元素序列
 */
template <typename T>
std::vector<T>
drain_stack_to_vector(std::stack<T> st)
{
    std::vector<T> out;
    while (!st.empty())
    {
        out.push_back(st.top());
        st.pop();
    }
    return out;
}

/**
 * 将 queue 中的元素按弹出顺序收集到向量
 * 参数:
 * - qu 输入的队列（按值传递）
 * 返回值: 依次弹出得到的元素序列（FIFO）
 */
template <typename T>
std::vector<T>
drain_queue_to_vector(std::queue<T> qu)
{
    std::vector<T> out;
    while (!qu.empty())
    {
        out.push_back(qu.front());
        qu.pop();
    }
    return out;
}

/**
 * 将 priority_queue 中的元素按弹出顺序收集到向量
 * 参数:
 * - pq 输入的优先队列（按值传递，可带任意容器与比较器）
 * 返回值: 依次弹出得到的元素序列（由比较器定义的优先级顺序）
 */
template <typename T, typename Container, typename Compare>
std::vector<T>
drain_priority_queue_to_vector(std::priority_queue<T, Container, Compare> pq)
{
    std::vector<T> out;
    while (!pq.empty())
    {
        out.push_back(pq.top());
        pq.pop();
    }
    return out;
}

TEST(cpo_adapter_containers_test, stack_int_roundtrip)
{
    default_options options{};

    std::stack<int> st;
    for (int i = 1; i <= 5; ++i)
        st.push(i);

    vector_writer writer;
    serialize(writer, st, options);
    vector_reader reader(writer.data());
    auto st_out = deserialize_cpo(reader, options, type_tag<std::stack<int>>);

    EXPECT_EQ(drain_stack_to_vector(st_out), drain_stack_to_vector(st));
}

TEST(cpo_adapter_containers_test, queue_string_roundtrip)
{
    default_options options{};

    std::queue<std::string> qu;
    qu.push("alpha");
    qu.push("beta");
    qu.push("gamma");

    vector_writer writer;
    serialize(writer, qu, options);
    vector_reader reader(writer.data());
    auto qu_out = deserialize_cpo(reader, options, type_tag<std::queue<std::string>>);

    EXPECT_EQ(drain_queue_to_vector(qu_out), drain_queue_to_vector(qu));
}

TEST(cpo_adapter_containers_test, priority_queue_double_roundtrip)
{
    default_options options{};

    std::priority_queue<double> pq;
    pq.push(3.14);
    pq.push(2.71);
    pq.push(42.0);

    vector_writer writer;
    serialize(writer, pq, options);
    vector_reader reader(writer.data());
    auto pq_out = deserialize_cpo(reader, options, type_tag<std::priority_queue<double>>);

    EXPECT_EQ(drain_priority_queue_to_vector(pq_out), drain_priority_queue_to_vector(pq));
}

TEST(cpo_adapter_containers_test, empty_adapters_roundtrip)
{
    default_options options{};

    std::stack<int> st;
    std::queue<int> qu;
    std::priority_queue<int> pq;

    vector_writer writer;
    serialize(writer, st, options);
    serialize(writer, qu, options);
    serialize(writer, pq, options);

    vector_reader reader(writer.data());
    auto st_out = deserialize_cpo(reader, options, type_tag<std::stack<int>>);
    auto qu_out = deserialize_cpo(reader, options, type_tag<std::queue<int>>);
    auto pq_out = deserialize_cpo(reader, options, type_tag<std::priority_queue<int>>);

    EXPECT_TRUE(drain_stack_to_vector(st_out).empty());
    EXPECT_TRUE(drain_queue_to_vector(qu_out).empty());
    EXPECT_TRUE(drain_priority_queue_to_vector(pq_out).empty());
}

TEST(cpo_adapter_containers_test, stack_linear_view_order_semantics)
{
    default_options options{};

    std::stack<int> st;
    for (int i = 1; i <= 5; ++i)
        st.push(i); // 底部=1, 顶部=5

    vector_writer writer;
    serialize(writer, st, options);
    vector_reader reader(writer.data());

    using underlying_t = typename std::stack<int>::container_type;
    auto underlying = deserialize_cpo(reader, options, type_tag<underlying_t>);

    // 线性视图应为自底向上: [1, 2, 3, 4, 5]
    std::vector<int> expected{1, 2, 3, 4, 5};
    std::vector<int> actual(underlying.begin(), underlying.end());
    EXPECT_EQ(actual, expected);
}

TEST(cpo_adapter_containers_test, queue_linear_view_order_semantics)
{
    default_options options{};

    std::queue<std::string> qu;
    qu.push("alpha");
    qu.push("beta");
    qu.push("gamma");

    vector_writer writer;
    serialize(writer, qu, options);
    vector_reader reader(writer.data());

    using underlying_t = typename std::queue<std::string>::container_type;
    auto underlying = deserialize_cpo(reader, options, type_tag<underlying_t>);

    // 线性视图应为 FIFO 顺序: [alpha, beta, gamma]
    std::vector<std::string> expected{"alpha", "beta", "gamma"};
    std::vector<std::string> actual(underlying.begin(), underlying.end());
    EXPECT_EQ(actual, expected);
}

TEST(cpo_adapter_containers_test, priority_queue_linear_view_order_semantics_default)
{
    default_options options{};

    std::priority_queue<double> pq; // 默认比较器: std::less<double>
    pq.push(3.14);
    pq.push(2.71);
    pq.push(42.0);

    // 期望的弹出序（top->pop）
    auto pq_expected = pq;
    std::vector<double> expected = drain_priority_queue_to_vector(std::move(pq_expected));

    vector_writer writer;
    serialize(writer, pq, options);
    vector_reader reader(writer.data());

    using underlying_t = typename std::priority_queue<double>::container_type;
    auto underlying = deserialize_cpo(reader, options, type_tag<underlying_t>);

    // 从线性视图重构适配器，再验证弹出序
    auto pq_out = serializer::reconstruct_adapter_from_container<std::priority_queue<double>>(
        std::move(underlying));
    std::vector<double> actual = drain_priority_queue_to_vector(std::move(pq_out));
    EXPECT_EQ(actual, expected);
}

TEST(cpo_adapter_containers_test, priority_queue_linear_view_order_semantics_custom_comparator)
{
    default_options options{};

    using min_heap_t =
        std::priority_queue<int, std::vector<int>, std::greater<int>>; // top 为最小值
    min_heap_t pq;
    pq.push(10);
    pq.push(5);
    pq.push(20);

    // 期望的弹出序（top->pop）
    auto pq_expected = pq;
    std::vector<int> expected = drain_priority_queue_to_vector(std::move(pq_expected));

    vector_writer writer;
    serialize(writer, pq, options);
    vector_reader reader(writer.data());

    using underlying_t = typename min_heap_t::container_type;
    auto underlying = deserialize_cpo(reader, options, type_tag<underlying_t>);

    // 从线性视图重构适配器，再验证弹出序
    auto pq_out = serializer::reconstruct_adapter_from_container<min_heap_t>(std::move(underlying));
    std::vector<int> actual = drain_priority_queue_to_vector(std::move(pq_out));
    EXPECT_EQ(actual, expected);
}